/*
 * KKNode.h
 *
 *  Created on: 2013-9-15
 *      Author: wanghua
 */

#ifndef KKNODE_H_
#define KKNODE_H_

#include "kaka_common.h"

#include "KKGestureDirector.h"
#include "KKEvent.h"
#include "KKTouch.h"
#include <iostream>
#include <vector>

using namespace std;

USING_NS_CC;

typedef enum {
	KKTYPE_NORMAL, KKTYPE_BUTTON, KKTYPE_DYNAMIC_BODY, KKTYPE_STATIC_BODY
} KKNodeType;

typedef enum {
	KKEFFECT_NONE,
	KKEFFECT_ZOOMIN,
	KKEFFECT_ZOOMOUT,
	KKEFFECT_ROTATE_LEFT,
	KKEFFECT_ROTATE_RIGHT,
	KKEFFECT_SHADOW
} KKClickEffect;

class KKNode;

class KKLayout;

typedef KKMutableArray<KKNode*> KKNodeArray;

typedef vector<KKNode*> KKObjectArray;

class KKNodeVertexes: public CCObject {
private:
	;CC_SYNTHESIZE(string,m_name,Name)
	;CC_SYNTHESIZE(string,m_type,Type)
	;CC_SYNTHESIZE(KKVertexArray*,m_vertexs,Vertexs)
	;
public:
	KKNodeVertexes() {
		m_vertexs = new KKVertexArray();
	}
	;
	virtual ~KKNodeVertexes() {
		CC_SAFE_DELETE(m_vertexs);
	}
	;

};

typedef enum {
	fix, fill_parent, wrap_content
} KKNodeSizeType;

typedef KKMutableArray<KKNodeVertexes*> KKNodeVertexesArray;
typedef KKDictionary<int, bool> KKTouchCache;

class KKNode: public KKGestureListener {

protected:

	;CC_SYNTHESIZE_READONLY(int,m_id,Id)
	;CC_SYNTHESIZE(string,m_name,Name)
	;CC_SYNTHESIZE(KKNodeType,m_type,Type)
	;CC_SYNTHESIZE(string,m_image,Image)
	;CC_SYNTHESIZE(string,m_hotImage,HotImage)
	;CC_SYNTHESIZE(string,m_disableImage,DisableImage)

	;CC_SYNTHESIZE(int,m_width,Width)
	;CC_SYNTHESIZE(int,m_height,Height)

	;CC_SYNTHESIZE(KKNodeSizeType,m_widthType,WidthType)
	;CC_SYNTHESIZE(KKNodeSizeType,m_heightType,HeightType)

	;CC_SYNTHESIZE(int,m_x,X)
	;CC_SYNTHESIZE(int,m_y,Y)

	;CC_SYNTHESIZE(float,m_layoutX,LayoutX)
	;CC_SYNTHESIZE(float,m_layoutY,LayoutY)

	;CC_SYNTHESIZE(int,m_zOrder,ZOrder)

	;CC_SYNTHESIZE_READONLY(float,m_minX,MinX)
	;CC_SYNTHESIZE_READONLY(float,m_minY,MinY)
	;CC_SYNTHESIZE_READONLY(float,m_maxX,MaxX)
	;CC_SYNTHESIZE_READONLY(float,m_maxY,MaxY)

	;CC_SYNTHESIZE(bool,m_isEnable,IsEnable)
	;CC_SYNTHESIZE(bool,m_isSoundEffect,IsSoundEffect)
	;CC_SYNTHESIZE(KKClickEffect,m_clickEffect,ClickEffect)

	;CC_PROPERTY(bool,m_isChildTouchable,IsChildTouchable)
	;CC_PROPERTY(bool,m_isTouchable,IsTouchable)
	;CC_SYNTHESIZE(bool,m_isSupportMultiTouch,IsSupportMultiTouch)

	;CC_SYNTHESIZE(bool,m_isDragable,IsDragable)
	;CC_SYNTHESIZE(bool,m_isMovable,IsMovable)
	;CC_SYNTHESIZE(bool,m_isRotatable,IsRotatable)
	;CC_SYNTHESIZE(bool,m_isZoomable,IsZoomable)

	;CC_SYNTHESIZE(bool,m_hasHotArea,HasHotArea)

	;CC_SYNTHESIZE_READONLY(bool,m_isItemTouchable,IsItemTouchable)
	;CC_SYNTHESIZE_READONLY(bool,m_isMoved,IsMoved)
	;CC_SYNTHESIZE(bool,m_selected,Selected)
	;CC_SYNTHESIZE(bool,m_used,Used)

	;CC_SYNTHESIZE_READONLY(TiXmlElement*,m_element,TiXmlElement)
	;CC_SYNTHESIZE(TiXmlDocument*,m_document,TiXmlDocument)

	;CC_SYNTHESIZE_READONLY(bool,m_isLoaded,IsLoaded)

	;CC_SYNTHESIZE(bool,m_isUseLocalTouch,IsUseLocalTouch)

	;CC_SYNTHESIZE(KKNode*,m_kkParent,KKParent)
	;CC_SYNTHESIZE_READONLY(CCLayerColor*,m_bgColor,BgColor)
	;CC_SYNTHESIZE_READONLY(CCLayerColor*,m_shadowEffectColor,ShadowEffectColor)

	;CC_SYNTHESIZE_READONLY(KKPropertiesDictionary*,m_properties,Properties)
	;CC_SYNTHESIZE_READONLY(KKEventDictionary*,m_events,Events)
	;CC_SYNTHESIZE_READONLY(KKNodeArray*,m_objects,Objects)

	;CC_SYNTHESIZE(KKNodeVertexesArray*,m_nodeVertexs,NodeVertexs)
	;
	;CC_SYNTHESIZE(KKLayout*,m_layout,Layout)
	;

	;CC_SYNTHESIZE(float,m_density,Density)
	;CC_SYNTHESIZE(float,m_friction,Friction)
	;CC_SYNTHESIZE(float,m_restitution,Restitution)
	;CC_SYNTHESIZE(bool,m_isSensor,IsSensor)

	;CC_SYNTHESIZE(float,m_velocityX,VelocityX)
	;CC_SYNTHESIZE(float,m_velocityY,VelocityY)

	;CC_SYNTHESIZE(b2Body*,m_body,Body)

	KKGestureDirector* m_GestureDirector;

	CCNode* m_ccNode;

	KKTouchCache touchHolder;

protected:

	const static int BG_COLOR_TAG = 1001;
	const static int BG_IMAGE_TAG = 1002;
	const static int SHADOW_COLOR_TAG = 1003;

	const static int BG_COLOR_ZORDER = -201;
	const static int BG_IMAGE_ZORDER = -200;
	const static int SHADOW_COLOR_ZORDER = 2000;

	virtual bool initWithXml(TiXmlElement* element, KKNode* parent);

	virtual bool initCommonInfoWithXml(TiXmlElement* element, KKNode* parent);

	virtual void initLayoutFromXml(TiXmlElement* element, KKNode* parent);

	virtual bool initDelayInfoWithXml(TiXmlElement* element);

private:
	void insertNode(KKNode* node, int zOrder);

protected:
	KKNode();
	KKNode(const KKNode& obj);
	KKNode& operator=(const KKNode& obj);
public:
	virtual ~KKNode();
public:

	friend class KKLayout;
	friend class GridLayout;
	friend class RelativeLayout;
	friend class LinearLayout;
	friend class AbsLayout;

	virtual void saveToXml(TiXmlElement* element);
	virtual KKNode* cloneNode(bool forceUpdate = false);
	virtual void initWithNode(KKNode* node);

	bool getBooleanProperty(string key, bool defaultValue = false);
	int getIntProperty(string key, int defaultValue = 0);
	float getFloatProperty(string key, float defaultValue = 0);
	string getStringProperty(string key, const char* defaultValue = "");

	void setProperty(string key, float value);
	void setProperty(string key, bool value);
	void setProperty(string key, const char* value);
	void setProperty(string key, int value);

public:
	virtual bool checkInTapArea(const CCPoint& point);
	virtual bool contains(KKNode* node);
	virtual CCPoint getLocalTouchPoint(const CCPoint& point);
	virtual bool contains(const CCPoint& touchPoint);

	virtual bool dispatchTouchDown(KKTouch& touch);
	virtual void dispatchTouchMove(KKTouch& touch);
	virtual void dispatchTouchUp(KKTouch& touch);
	virtual void dispatchTouchCancel(KKTouch& touch);

	virtual bool onTouchDown(KKTouch& touch);
	virtual void onTouchMove(KKTouch& touch);
	virtual void onTouchUp(KKTouch& touch);
	virtual void onTouchCancel(KKTouch& touch);

	virtual void onFling(const KKTouch& touch, const CCPoint& velocity);
	virtual void onScroll(const KKTouch& touch, const CCPoint& dir);
	virtual void onLongDown(const KKTouch& touch);
	virtual void onTap(const KKTouch& touch);
	virtual void onDown(const KKTouch& touch);
	virtual void onUp(const KKTouch& touch);

	virtual void onContact(KKNode* contactNode);

	//BeginContact, EndContact, PreSolve, PostSolve
	virtual void onBeginContact(KKNode* contactNode);
	virtual void onEndContact(KKNode* contactNode);
	virtual void onPreSolve(KKNode* contactNode);
	virtual void onPostSolve(KKNode* contactNode);

	virtual void onBeginContact(b2Body* body);
	virtual void onEndContact(b2Body* body);
	virtual void onPreSolve(b2Body* body);
	virtual void onPostSolve(b2Body* body);

	virtual void onDrag(const CCPoint& drag);
	virtual void onZoom(const CCPoint& zoom);
	virtual void onRotate(const float& angle);

	virtual void onInit();

	bool performEvent(string eventName, KKEventActionArgs* args);

	void registerEventHandler(string eventName, string handlerName,
			bool override = true);

	void registerEventHandler(string eventName, SEL_CallFuncND eventFunc,
			CCObject* target = NULL, bool override = true);

	virtual void setIsVisible(bool isVisible)=0;
	virtual bool getIsVisible()=0;

	void setAnchorPointNotChangePosition(const CCPoint& anchorPoint);

	float getScaledWidth();
	float getScaledHeight();

	//virtual void setAnchorPoint(CCPoint& anchorPoint)=0;

	KKNode* findNodeById(int id);
	KKNode* nodeNamed(string nodeName, bool includeInvisiable = false);
	KKNode* findNodeByProperty(string propertyName, int propertyValue);
	KKNode* findNodeByProperty(string propertyName, const char* propertyValue);
	KKObjectArray* findNodesByProperty(string propertyName, int propertyValue);

	virtual void reorderNode(KKNode* node, int zOrder);
	virtual bool addNode(KKNode* node, int zOrder = 0, int tag = -1);
	virtual void removeNode(KKNode* node, bool cleanup = false);
	virtual void removeNodeByTag(int tag, bool cleanup = false);
	virtual void removeAllNodes(bool cleanup = false);

	virtual CCSize measureInnerSize();

	bool checkAutoLoad();
	bool loadNode();
	void unloadNode();
	virtual void resetNode(bool reload = false, bool stopAction = false);
	virtual void pauseNode();
	virtual void resumeNode();

	virtual void resize(const float& width, const float& height);

	virtual void measure();

	virtual void layout();

	void runStoryboard(const char* storyboardName);

	bool checkTouchable() {
		return m_isEnable && getIsVisible()
				&& (m_isTouchable || m_isChildTouchable);
	}

	inline CCNode* convertToCCNode() {
		return dynamic_cast<CCNode*>(this);
	}

	bool isPhysics() {
		return m_type == KKTYPE_DYNAMIC_BODY || m_type == KKTYPE_STATIC_BODY;
	}
	;

	b2BodyType getBox2dPhysicsType() {
		return m_type == KKTYPE_DYNAMIC_BODY ? b2_dynamicBody : b2_staticBody;
	}
	;

	inline int getTouchCount() {
		return int(touchHolder.count());
	}
	inline bool isInTouch(const int viewId) {
		return touchHolder.contains(viewId);
	}
	;

	inline void setInTouch(const int viewId, bool isInTouch) {

		if (isInTouch) {
			touchHolder.setObject(isInTouch, viewId);
		} else {
			touchHolder.removeObjectForKey(viewId);
		}
	}
	;

};

class KKNodeParser: public CCObject {

private:

	static KKNodeParser* m_defaultParser;

	static KKDictionary<string, KKNodeParser*> m_parsers;

public:
	KKNodeParser() {
	}
	;
	virtual ~KKNodeParser() {
	}
	;

	virtual KKNode* parse(TiXmlElement* element, KKNode* parent) = 0;

public:

	static KKNodeParser* getParser(TiXmlElement* element);

	static KKNode* parseFromXml(TiXmlElement* element, KKNode* parent);

	static void registerParser(const char* className, KKNodeParser* parser) {
		m_parsers.setObject(parser, className);
	}

};

class KKDefaultParser: public KKNodeParser {
	KKNode* parse(TiXmlElement* element, KKNode* parent) {
		return NULL;
	}
};

#define KKNODE_FACTORY_METHOD(className,methodName) \
		static className* methodName(TiXmlElement* element, KKNode* parent) {\
			className* node = new className();\
			if (node->initWithXml(element, parent)) {\
				node->autorelease();\
				return node;\
			}\
			CC_SAFE_DELETE(node);\
			return NULL;\
		};\
		static className* methodName##File(const char *pszFileName, KKNode* parent) {\
			TiXmlDocument *myDocument = XmlUtils::readXML(pszFileName);\
			return methodName(myDocument->RootElement(), parent);\
		};

#define KKNODE_PARSER_CLASS(parserClass,className,factoryMethod) \
		class parserClass: public KKNodeParser {\
			KKNode* parse(TiXmlElement* element, KKNode* parent) {\
				return className::factoryMethod(element, parent);\
			}\
		};

#define KK_NODE_CONTENT_WIDTH(node,w) \
		KKNodeArray* objects = node->getObjects();\
		KKNodeArray::CCMutableArrayIterator it = objects->begin();\
		while(it!=objects->end()){\
			w+=getChildWidth(*it);\
			it++;\
		}

#define KK_NODE_CONTENT_HEIGHT(node,h) \
		KKNodeArray* objects = node->getObjects();\
		KKNodeArray::CCMutableArrayIterator it = objects->begin();\
		while(it!=objects->end()){\
			h+=getChildHeight(*it);\
			it++;\
		}

#define KKNODE_FOREACH(objects,child) \
		for(KKNodeArray::CCMutableArrayIterator it = objects->begin();it!=objects->end()&&(child=*it);it++)

#endif /* KKNODE_H_ */
